﻿using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;

namespace UniversityPhoneCrawlerImproved
{
    class Program
    {
        private static readonly Regex _phoneRegex = new Regex(
            @"
            (?:
                (?:\+?86)?\s*                # 可选的国家代码（+86或86）
                (?:\(?0\d{2,3}\)?)[-\s]?     # 区号（如010、(021)）
                \d{7,8}                      # 基本号码
                (?:-\d{1,4})?                # 可选分机号
            )
            |
            (?:
                1[3-9]\d{9}                  # 手机号码
            )",
            RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline);

        private static readonly Dictionary<string, List<string>> _phoneNumbers = new Dictionary<string, List<string>>();
        private static readonly List<string> _visitedUrls = new List<string>();
        private static readonly SemaphoreSlim _semaphore = new SemaphoreSlim(2); 
        private static readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
        private const int MaxPhoneNumbers = 50;
        private static readonly HttpClient _httpClient = CreateHttpClient();

        static HttpClient CreateHttpClient()
        {
            var handler = new HttpClientHandler
            {
                UseCookies = true,
                AutomaticDecompression = System.Net.DecompressionMethods.GZip | System.Net.DecompressionMethods.Deflate
            };

            var client = new HttpClient(handler);
            client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36");
            client.DefaultRequestHeaders.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
            client.DefaultRequestHeaders.Add("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8");
            client.DefaultRequestHeaders.Add("Connection", "keep-alive");
            return client;
        }

        static async Task Main(string[] args)
        {
            Console.WriteLine("=== 高校电话号码爬虫 ===");
            Console.WriteLine("提示：直接输入高校名称（如'清华大学'）或手动输入网址（如'https://www.tsinghua.edu.cn'）");
            Console.Write("请输入搜索内容: ");
            string input = Console.ReadLine();

            if (string.IsNullOrEmpty(input))
            {
                Console.WriteLine("输入不能为空!");
                return;
            }

            try
            {
                Console.WriteLine("开始爬取...");

                if (input.StartsWith("http", StringComparison.OrdinalIgnoreCase))
                {
                    await CrawlUrlAsync(input);
                }
                else
                {
                    await SearchAndCrawl(input);
                }

                Console.WriteLine("\n=== 爬取完成 ===");
                Console.WriteLine($"共爬取 {_visitedUrls.Count} 个URL");
                Console.WriteLine($"找到 {_phoneNumbers.Count} 个电话号码");

                if (_phoneNumbers.Count > 0)
                {
                    Console.WriteLine("\n电话号码列表:");
                    foreach (var phone in _phoneNumbers)
                    {
                        Console.WriteLine($"{phone.Key} - 来源: {string.Join(" | ", phone.Value)}");
                    }
                }
                else
                {
                    Console.WriteLine("未找到任何电话号码，请尝试调整搜索关键词或正则表达式。");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"发生错误: {ex.Message}");
            }

            Console.WriteLine("\n按任意键退出...");
            Console.ReadKey();
        }

        static async Task SearchAndCrawl(string keyword)
        {
 
            string searchUrl = $"https://cn.bing.com/search?q={System.Web.HttpUtility.UrlEncode(keyword + " 电话")}";
            string searchHtml = await FetchUrlContent(searchUrl);

            
            List<string> resultUrls = ExtractUrlsFromSearchResult(searchHtml);

            Console.WriteLine($"找到 {resultUrls.Count} 个搜索结果，开始爬取...");

            
            var tasks = new List<Task>();
            foreach (string url in resultUrls)
            {
                if (_phoneNumbers.Count >= MaxPhoneNumbers)
                    break;

                tasks.Add(CrawlUrlAsync(url));
            }

            await Task.WhenAll(tasks);
        }

        static async Task<string> FetchUrlContent(string url)
        {
            try
            {
                await _semaphore.WaitAsync(_cancellationTokenSource.Token);
                Console.WriteLine($"正在爬取: {url}");
                _visitedUrls.Add(url);

                
                await Task.Delay(new Random().Next(500, 2000));

                HttpResponseMessage response = await _httpClient.GetAsync(url, _cancellationTokenSource.Token);
                response.EnsureSuccessStatusCode();
                return await response.Content.ReadAsStringAsync();
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error fetching {url}: {ex.Message}");
                return string.Empty;
            }
            finally
            {
                _semaphore.Release();
            }
        }

        static List<string> ExtractUrlsFromSearchResult(string html)
        {
            List<string> urls = new List<string>();
           
            MatchCollection matches = Regex.Matches(html, @"<h2><a href=""(https?://[^""]+)""");

            foreach (Match match in matches)
            {
                if (match.Groups.Count > 1)
                {
                    string url = match.Groups[1].Value;
                    
                    if (url.Contains("edu.cn") || url.Contains("university") || url.Contains("college"))
                    {
                        urls.Add(url);
                    }
                }
            }
            return urls;
        }

        static async Task CrawlUrlAsync(string url)
        {
            if (_phoneNumbers.Count >= MaxPhoneNumbers)
                return;

            string html = await FetchUrlContent(url);
            if (string.IsNullOrEmpty(html))
                return;

            // 提取电话号码
            MatchCollection matches = _phoneRegex.Matches(html);
            foreach (Match match in matches)
            {
                if (_phoneNumbers.Count >= MaxPhoneNumbers)
                    break;

                string phone = CleanPhoneNumber(match.Value);
                if (!string.IsNullOrEmpty(phone) && !_phoneNumbers.ContainsKey(phone))
                {
                    _phoneNumbers[phone] = new List<string> { url };
                    Console.WriteLine($"找到新号码: {phone}");
                }
                else if (!string.IsNullOrEmpty(phone) && !_phoneNumbers[phone].Contains(url))
                {
                    _phoneNumbers[phone].Add(url);
                }
            }
        }

        static string CleanPhoneNumber(string phone)
        {
            // 清理电话号码格式，统一为纯数字
            return Regex.Replace(phone, @"[^\d]", "");
        }
    }
}